from datetime import datetime

from flask import current_app

from app import db
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from . import login_manager
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer


@login_manager.user_loader
def load_user(user_id):
    return UserInfo.query.get(int(user_id))


class Permission:
    FOLLOW = 1
    COMMENT = 2
    WRITE = 4
    MODERATE = 8
    ADMIN = 16


class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    # 指明一般用户默认的角色
    default = db.Column(db.Boolean, default=False, index=True)
    # permissions字段用来记录不同角色的权限值
    permissions = db.Column(db.Integer)
    users = db.relationship('UserInfo', backref='role', lazy='dynamic')

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        if self.permissions is None:
            self.permissions = 0

    # 添加权限
    def add_permission(self, perm):
        if self.has_permission(perm):
            self.permissions += perm

    # 删除权限
    def remove_permission(self, perm):
        if self.has_permission(perm):
            self.permissions -= perm

    # 清除权限
    def reset_permission(self):
        self.permissions = 0

    # 判断是否存在某个权限
    def has_permission(self, perm):
        return self.permissions & perm == perm


class UserInfo(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True)
    sex = db.Column(db.String(5))
    password_hash = db.Column(db.String(50))
    email = db.Column(db.String(64), nullable=True)
    confirmed = db.Column(db.Boolean, default=False)
    telbooks = db.relationship('TelBook', backref='users')
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __init__(self, **kwargs):
        super(UserInfo, self).__init__(**kwargs)
        if self.role is None:
            self.role = Role.query.filter_by(default=True).first()

    # 禁止读取密码
    @property
    def password(self):
        raise AttributeError("密码不可访问")

    # 设置密码
    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    # 验证密码，密码正确返回True
    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

    # 确认密码加密
    def generate_confirmation_token(self, expiration=3600):
        s = Serializer(current_app.config["SECRET_KEY"], expiration)
        return s.dumps({"confirm": self.id}).decode('utf-8')

    # 解密
    def confirm(self, token):
        s = Serializer(current_app.config["SECRET_KEY"])
        try:
            data = s.loads(token.encode('utf-8'))
        except Exception as e:
            return False
        if data.get('confirm') != self.id:
            return False
        self.confirmed = True
        db.session.add(self)
        return True

    def __repr__(self):
        return "<UserInfo %s>" % self.username


class TypeTel(db.Model):
    __tablename__ = 'typetels'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    telbooks = db.relationship("TelBook", backref='typetels')

    def __repr__(self):
        return "<TypeTel %s>" % self.name


class TelBook(db.Model):
    __tablename__ = 'telbooks'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    tel = db.Column(db.String(11))
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    typetel_id = db.Column(db.Integer, db.ForeignKey('typetels.id'))

    def __repr__(self):
        return "<TelBook %s>" % self.name


class Log(db.Model):
    __tablename__ = 'logs'
    id = db.Column(db.Integer, primary_key=True)
    ip = db.Column(db.String(100))
    user = db.Column(db.String(50), nullable=True)
    page = db.Column(db.String(100))
    option = db.Column(db.String(100))
    create_time = db.Column(db.DateTime, default=datetime.utcnow())
